
#ifndef M_SINK_H__
#define M_SINK_H__
#include"utils.hpp"
#include"message.hpp"
#include"format.hpp"
#include <memory>
#include <cassert>

namespace tclog{
    class LogSink{
        public:
            using ptr = std::shared_ptr<LogSink>;
            virtual ~LogSink(){}
            virtual void log(const char* data,size_t len) = 0;
    };
    //标准输出
    class StdoutSink:public LogSink{
        public:
            virtual void log(const char* data,size_t len) override{
                //不用<<是因为以\0结尾，但日志输出不一定是字符串
                std::cout.write(data,len);
            }
    };
    //指定文件
    class FileSink:public LogSink{
        public:
            FileSink(const std::string& filename):_filename(filename){
                //1.创建文件所在目录
                util::File::create_directory(util::File::path(filename));
                //2.创建并打开文件 
                _ofs.open(filename,std::ios::binary|std::ios::app);
                assert(_ofs.is_open());
            }
        virtual void log(const char* data,size_t len) override{
            _ofs.write(data,len);
            _ofs.flush();    //因为忘记刷新缓冲区会导致数据没有立即写入文件
            assert(_ofs.good());
        }
        private:
            std::string _filename;
            std::ofstream _ofs;
    };

    class RollSink:public LogSink{
        public:
            RollSink(const std::string& basename,size_t maxFileSize):
            _baseName(basename),
            _maxFileSize(maxFileSize),
            _curFileSize(0){
                assert(maxFileSize>0);
                std::string filename= create_newfile();
                //1.创建文件所在目录
                util::File::create_directory(util::File::path(filename));
                //2.创建并打开文件 
                _ofs.open(filename,std::ios::binary|std::ios::app);
               assert(_ofs.is_open());
            }
            virtual void log(const char* data,size_t len) override{
                if(_curFileSize>=_maxFileSize){
                    _ofs.close();
                    _ofs.open(create_newfile(),std::ios::binary|std::ios::app);
                    assert(_ofs.is_open());
                    _curFileSize=0;
                }
                _ofs.write(data,len);
                assert(_ofs.good());
                _curFileSize+=len;

            }

        private:
            std::string create_newfile(){
                //生成新的日志文件名
                time_t t=time(nullptr);
                struct tm lt;
                localtime_r(&t,&lt);
                char tmp[128];
                strftime(tmp,127,"%Y%m%d%H%M%S",&lt);
                return _baseName+tmp+"-"+std::to_string(_fileIndex++) +".log";
            }
            std::string _baseName;
            size_t _maxFileSize;
            size_t _curFileSize;
            size_t _fileIndex=0;
            std::ofstream _ofs;
    };
    
    
    class SinkFactory{
        public:
            template<typename SinkType,typename... Args>
            static LogSink::ptr create(Args&&... args){
                return std::make_shared<SinkType>(std::forward<Args>(args)...); //

            }
    };
    
}

#endif